package city.spring.modules.work.controller;

import city.spring.modules.system.entity.UserEntity;
import city.spring.modules.system.mapstruct.SimpleUserVoMapStruct;
import city.spring.modules.system.service.UserService;
import city.spring.modules.system.vo.SimpleUserVO;
import city.spring.modules.work.entity.WorkReplaceApplyEntity;
import city.spring.modules.work.entity.WorkScheduleItemEntity;
import city.spring.modules.work.entity.WorkScheduleShiftEntity;
import city.spring.modules.work.mapstruct.WorkReplaceApplyScheduleItemMapStruct;
import city.spring.modules.work.mapstruct.WorkReplaceApplyVoMapStruct;
import city.spring.modules.work.service.WorkReplaceApplyService;
import city.spring.modules.work.service.WorkScheduleItemService;
import city.spring.modules.work.service.WorkScheduleShiftService;
import city.spring.modules.work.vo.WorkReplaceApplyScheduleItemVO;
import city.spring.modules.work.vo.WorkReplaceApplyVO;
import city.spring.utils.MyBatisUtils;
import city.spring.utils.OrganizationUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.api.ApiController;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Controller：值班替班申请表
 *
 * @author 侯坤林
 * @date 2020-06-28 10:24:34
 */
@RestController
@RequestMapping("/work_replace_apply")
public class WorkReplaceApplyController extends ApiController {
    private final WorkReplaceApplyService workReplaceApplyService;
    private final WorkScheduleItemService scheduleItemService;
    private final UserService userService;
    private final WorkReplaceApplyVoMapStruct workReplaceApplyVoMapStruct;
    private final SimpleUserVoMapStruct simpleUserVoMapStruct;
    private final WorkReplaceApplyScheduleItemMapStruct workReplaceApplyScheduleItemMapStruct;
    private final WorkScheduleShiftService workScheduleShiftService;
    /**
     * 实体类可排序字段
     */
    private final List<SFunction<WorkReplaceApplyEntity, ?>> entityOrderFields;

    public WorkReplaceApplyController(WorkReplaceApplyService workReplaceApplyService, WorkScheduleItemService scheduleItemService, UserService userService, WorkReplaceApplyVoMapStruct workReplaceApplyVoMapStruct, SimpleUserVoMapStruct simpleUserVoMapStruct, WorkReplaceApplyScheduleItemMapStruct workReplaceApplyScheduleItemMapStruct, WorkScheduleShiftService workScheduleShiftService) {
        this.workReplaceApplyService = workReplaceApplyService;
        this.scheduleItemService = scheduleItemService;
        this.userService = userService;
        this.workReplaceApplyVoMapStruct = workReplaceApplyVoMapStruct;
        this.simpleUserVoMapStruct = simpleUserVoMapStruct;
        this.workReplaceApplyScheduleItemMapStruct = workReplaceApplyScheduleItemMapStruct;
        this.workScheduleShiftService = workScheduleShiftService;
        entityOrderFields = new ArrayList<>();
        entityOrderFields.add(WorkReplaceApplyEntity::getId);
        entityOrderFields.add(WorkReplaceApplyEntity::getUserId);
        entityOrderFields.add(WorkReplaceApplyEntity::getSourceId);
        entityOrderFields.add(WorkReplaceApplyEntity::getTargetWorkScheduleId);
        entityOrderFields.add(WorkReplaceApplyEntity::getTargetWorkScheduleDate);
        entityOrderFields.add(WorkReplaceApplyEntity::getTargetWorkScheduleShiftId);
        entityOrderFields.add(WorkReplaceApplyEntity::getTargetWorkScheduleItemId);
        entityOrderFields.add(WorkReplaceApplyEntity::getResult);
        entityOrderFields.add(WorkReplaceApplyEntity::getReview);
        entityOrderFields.add(WorkReplaceApplyEntity::getGmtCreated);
        entityOrderFields.add(WorkReplaceApplyEntity::getGmtModified);
    }

    /**
     * 获取全部的 <strong>值班替班申请表</strong> 列表
     */
    @GetMapping("all")
    public Object listAll(@PageableDefault Pageable pageable, WorkReplaceApplyEntity entity) {
        LambdaQueryChainWrapper<WorkReplaceApplyEntity> lambdaQuery = buildLambdaQuery(entity);
        OrganizationUtils.includes(lambdaQuery, WorkReplaceApplyEntity::getOrgId);
        MyBatisUtils.lambdaQueryAddOrder(lambdaQuery, pageable, entityOrderFields);
        return success(lambdaQuery.list());
    }

    /**
     * 分页获取 <strong>值班替班申请表</strong> 列表
     *
     * @param pageable 分页参数信息
     */
    @GetMapping
    public Object list(@PageableDefault Pageable pageable, WorkReplaceApplyEntity entity) {
        LambdaQueryChainWrapper<WorkReplaceApplyEntity> lambdaQuery = buildLambdaQuery(entity);
        OrganizationUtils.includes(lambdaQuery, WorkReplaceApplyEntity::getOrgId);
        MyBatisUtils.lambdaQueryAddOrder(lambdaQuery, pageable, entityOrderFields);
        Page<WorkReplaceApplyEntity> page = lambdaQuery.page(MyBatisUtils.toPage(pageable, false));

        List<WorkReplaceApplyEntity> records = page.getRecords();

        Set<String> userIds = records.stream().map(WorkReplaceApplyEntity::getUserId).collect(Collectors.toSet());

        Map<String, WorkReplaceApplyScheduleItemVO> scheduleItemMap = new HashMap<>();
        Map<String, SimpleUserVO> userMap = new HashMap<>();

        loadWorkScheduleItemEntity(scheduleItemMap, userMap, userIds, records);

        List<WorkReplaceApplyEntity> results = new ArrayList<>();
        for (WorkReplaceApplyEntity applyEntity : records) {
            WorkReplaceApplyVO workReplaceApplyVO = workReplaceApplyVoMapStruct.toVo(applyEntity);
            workReplaceApplyVO.setUser(userMap.get(applyEntity.getUserId()));
            workReplaceApplyVO.setSource(scheduleItemMap.get(applyEntity.getSourceId()));
            workReplaceApplyVO.setTarget(scheduleItemMap.get(applyEntity.getTargetWorkScheduleItemId()));
            results.add(workReplaceApplyVO);
        }

        page.setRecords(results);

        return success(page);
    }

    private void loadWorkScheduleItemEntity(Map<String, WorkReplaceApplyScheduleItemVO> scheduleItemMap,
                                            Map<String, SimpleUserVO> userMap,
                                            Set<String> userIds,
                                            List<WorkReplaceApplyEntity> records) {
        Set<String> scheduleItemIds = records.stream()
                .flatMap(item -> Stream.of(item.getSourceId(), item.getTargetWorkScheduleItemId()))
                .collect(Collectors.toSet());
        scheduleItemIds.remove(null);

        if (!scheduleItemIds.isEmpty()) {
            /*
             *
             WorkScheduleItemRepository scheduleItemRepository = (WorkScheduleItemRepository) scheduleItemService.getBaseMapper();
             QueryWrapper<WorkScheduleItemEntity> query = Wrappers.query();
             query.in("t1.id", scheduleItemIds);

             List<WorkScheduleItemVO> scheduleItems = scheduleItemRepository.getItems(query);
             */
            // 获取本次分页的所有上班记录信息
            List<WorkScheduleItemEntity> scheduleItems = scheduleItemService.lambdaQuery()
                    .in(WorkScheduleItemEntity::getId, scheduleItemIds)
                    .list();

            // 加载所有的用户信息
            loadUserEntity(userMap, userIds, scheduleItems);
            // 加载所有的上班班次列表
            Map<String, WorkScheduleShiftEntity> shifts = loadShift(scheduleItems);

            scheduleItems.forEach(item -> {
                WorkReplaceApplyScheduleItemVO itemVO = workReplaceApplyScheduleItemMapStruct.toVo(item);
                itemVO.setUser(userMap.get(itemVO.getUserId()));
                itemVO.setShift(shifts.get(itemVO.getWorkScheduleShiftId()));

                scheduleItemMap.put(item.getId(), itemVO);
            });

        }
    }

    /**
     * 加载本次分页的所有用户信息+上班记录的用户信息
     *
     * @param userMap       存储用户信息的map对象
     * @param userIds       用户ID列表
     * @param scheduleItems 上班记录信息
     */
    private void loadUserEntity(Map<String, SimpleUserVO> userMap, Set<String> userIds, List<WorkScheduleItemEntity> scheduleItems) {
        Set<String> set = scheduleItems.stream()
                .map(WorkScheduleItemEntity::getUserId)
                .collect(Collectors.toSet());
        userIds.addAll(set);
        if (!userIds.isEmpty()) {
            List<UserEntity> userEntities = userService.lambdaQuery()
                    .select(UserEntity::getId, UserEntity::getOrgId, UserEntity::getNickname, UserEntity::getType, UserEntity::getAvatar)
                    .in(UserEntity::getId, userIds)
                    .list();
            userEntities.forEach(item -> userMap.put(item.getId(), simpleUserVoMapStruct.toVo(item)));
        }
    }

    /**
     * 加载上班班次列表
     *
     * @param scheduleItems 上班班次列表
     */
    private Map<String, WorkScheduleShiftEntity> loadShift(List<WorkScheduleItemEntity> scheduleItems) {
        Map<String, WorkScheduleShiftEntity> map = new HashMap<>();

        Set<String> set = scheduleItems.stream()
                .map(WorkScheduleItemEntity::getWorkScheduleShiftId)
                .collect(Collectors.toSet());

        if (!set.isEmpty()) {
            List<WorkScheduleShiftEntity> userEntities = workScheduleShiftService.lambdaQuery()
                    .in(WorkScheduleShiftEntity::getId, set)
                    .list();
            userEntities.forEach(item -> map.put(item.getId(), item));
        }

        return map;
    }

    /**
     * 获取一个 <strong>值班替班申请表</strong>
     *
     * @param id 主键ID
     */
    @GetMapping("{id}")
    public Object info(@PathVariable String id) {
        return success(workReplaceApplyService.getById(id));
    }

    /**
     * 添加一个 <strong>值班替班申请表</strong>
     *
     * @param entity 修改后的信息
     */
    @PostMapping
    public Object add(@RequestBody WorkReplaceApplyEntity entity) {
        workReplaceApplyService.saveWorkReplaceApply(entity);

        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.LOCATION, String.valueOf(entity.getId()));
        return new ResponseEntity<>(headers, HttpStatus.CREATED);
    }

    /**
     * 修改一个 <strong>值班替班申请表</strong>
     *
     * @param id     主键ID
     * @param entity 修改后的信息
     */
    @PutMapping("{id}")
    public Object update(@PathVariable String id, @RequestBody WorkReplaceApplyEntity entity) {
        entity.setId(id);
        workReplaceApplyService.updateWorkReplaceApply(entity);
        return new ResponseEntity<>(HttpStatus.OK);
    }

    /**
     * 审核一个 <strong>值班替班申请</strong>
     *
     * @param id     主键ID
     * @param entity 修改后的信息
     * @see WorkReplaceApplyService#auditWorkReplaceApply(WorkReplaceApplyEntity)
     */
    @PutMapping("{id}/audit")
    public Object audit(@PathVariable String id, @RequestBody WorkReplaceApplyEntity entity) {
        entity.setId(id);
        workReplaceApplyService.auditWorkReplaceApply(entity);
        return new ResponseEntity<>(HttpStatus.OK);
    }

    /**
     * 删除一个 <strong>值班替班申请表</strong>
     *
     * @param id 主键ID
     */
    @DeleteMapping("{id}")
    public Object delete(@PathVariable String id) {
        workReplaceApplyService.deleteWorkReplaceApply(id);
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }

    /**
     * 删除多个 <strong>值班替班申请表</strong>
     *
     * @param ids 主键ID列表
     */
    @DeleteMapping
    public Object deleteIds(@RequestBody List<String> ids) {
        workReplaceApplyService.deleteWorkReplaceApply(ids);
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }

    /**
     * 构建查询条件内容
     *
     * @param entity 实体对象
     * @return lambda query chain wrapper
     */
    private LambdaQueryChainWrapper<WorkReplaceApplyEntity> buildLambdaQuery(WorkReplaceApplyEntity entity) {
        LambdaQueryChainWrapper<WorkReplaceApplyEntity> lambdaQuery = workReplaceApplyService.lambdaQuery();
        lambdaQuery.eq(StringUtils.isNotBlank(entity.getId()), WorkReplaceApplyEntity::getId, entity.getId());
        lambdaQuery.like(StringUtils.isNotBlank(entity.getUserId()), WorkReplaceApplyEntity::getUserId, entity.getUserId());
        lambdaQuery.like(StringUtils.isNotBlank(entity.getSourceId()), WorkReplaceApplyEntity::getSourceId, entity.getSourceId());
        lambdaQuery.like(StringUtils.isNotBlank(entity.getTargetWorkScheduleId()), WorkReplaceApplyEntity::getTargetWorkScheduleId, entity
                .getTargetWorkScheduleId());
        lambdaQuery.eq(entity.getTargetWorkScheduleDate() != null, WorkReplaceApplyEntity::getTargetWorkScheduleDate, entity
                .getTargetWorkScheduleDate());
        lambdaQuery.like(StringUtils.isNotBlank(entity.getTargetWorkScheduleShiftId()), WorkReplaceApplyEntity::getTargetWorkScheduleShiftId, entity
                .getTargetWorkScheduleShiftId());
        lambdaQuery.like(StringUtils.isNotBlank(entity.getTargetWorkScheduleItemId()), WorkReplaceApplyEntity::getTargetWorkScheduleItemId, entity
                .getTargetWorkScheduleItemId());
        lambdaQuery.eq(entity.getResult() != null, WorkReplaceApplyEntity::getResult, entity.getResult());
        lambdaQuery.like(StringUtils.isNotBlank(entity.getReview()), WorkReplaceApplyEntity::getReview, entity.getReview());
        lambdaQuery.eq(entity.getGmtCreated() != null, WorkReplaceApplyEntity::getGmtCreated, entity.getGmtCreated());
        lambdaQuery.eq(entity.getGmtModified() != null, WorkReplaceApplyEntity::getGmtModified, entity.getGmtModified());
        return lambdaQuery;
    }

    /**
     * 构建查询条件内容
     *
     * @param entity 实体对象
     * @return lambda query chain wrapper
     */
    private QueryWrapper<WorkReplaceApplyEntity> buildQuery(WorkReplaceApplyEntity entity) {
        QueryWrapper<WorkReplaceApplyEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(StringUtils.isNotBlank(entity.getId()), "id", entity.getId());
        wrapper.like(StringUtils.isNotBlank(entity.getUserId()), "user_id", entity.getUserId());
        wrapper.like(StringUtils.isNotBlank(entity.getSourceId()), "source_id", entity.getSourceId());
        wrapper.like(StringUtils.isNotBlank(entity.getTargetWorkScheduleId()), "target_work_schedule_id", entity.getTargetWorkScheduleId());
        wrapper.eq(entity.getTargetWorkScheduleDate() != null, "target_work_schedule_date", entity.getTargetWorkScheduleDate());
        wrapper.like(StringUtils.isNotBlank(entity.getTargetWorkScheduleShiftId()), "target_work_schedule_shift_id", entity
                .getTargetWorkScheduleShiftId());
        wrapper.like(StringUtils.isNotBlank(entity.getTargetWorkScheduleItemId()), "target_work_schedule_item_id", entity
                .getTargetWorkScheduleItemId());
        wrapper.eq(entity.getResult() != null, "result", entity.getResult());
        wrapper.like(StringUtils.isNotBlank(entity.getReview()), "review", entity.getReview());
        wrapper.eq(entity.getGmtCreated() != null, "gmt_created", entity.getGmtCreated());
        wrapper.eq(entity.getGmtModified() != null, "gmt_modified", entity.getGmtModified());
        return wrapper;
    }

}
